<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数据库迁移工具</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
    <!-- 添加mermaid.js用于绘制关系图 -->
    <script src="https://cdn.jsdelivr.net/npm/mermaid@10.6.1/dist/mermaid.min.js"></script>
    <style>
        body {
            padding-top: 20px;
            background-color: #f8f9fa;
        }

        .container {
            max-width: 1200px;
        }

        .card {
            margin-bottom: 20px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }

        .card-header {
            background-color: #f1f8ff;
        }

        .btn-primary {
            background-color: #0d6efd;
        }

        .table-container {
            max-height: 300px;
            overflow-y: auto;
        }

        #relationshipDiagram {
            width: 100%;
            overflow: auto;
            background-color: white;
            padding: 15px;
            border-radius: 5px;
        }
    </style>
</head>

<body>
    <div class="container">
        <h1 class="text-center mb-4">数据库迁移工具</h1>

        <div class="row">
            <!-- 源数据库配置 -->
            <div class="col-md-6">
                <div class="card">
                    <div class="card-header">
                        <h5>源数据库</h5>
                    </div>
                    <div class="card-body">
                        <form id="sourceDbForm">
                            <div class="mb-3">
                                <label for="sourceDbType" class="form-label">数据库类型</label>
                                <select class="form-select" id="sourceDbType" required>
                                    <option value="0">SQL Server</option>
                                    <option value="1">MySQL</option>
                                    <option value="2">PostgreSQL</option>
                                    <option value="3">SQLite</option>
                                </select>
                            </div>
                            <div class="mb-3" id="sourceServerField">
                                <label for="sourceServer" class="form-label">服务器</label>
                                <input type="text" class="form-control" id="sourceServer" placeholder="localhost">
                            </div>
                            <div class="mb-3" id="sourcePortField">
                                <label for="sourcePort" class="form-label">端口</label>
                                <input type="text" class="form-control" id="sourcePort" placeholder="1433">
                            </div>
                            <div class="mb-3">
                                <label for="sourceDatabase" class="form-label">数据库名</label>
                                <input type="text" class="form-control" id="sourceDatabase" required>
                            </div>
                            <div class="mb-3" id="sourceUsernameField">
                                <label for="sourceUsername" class="form-label">用户名</label>
                                <input type="text" class="form-control" id="sourceUsername">
                            </div>
                            <div class="mb-3" id="sourcePasswordField">
                                <label for="sourcePassword" class="form-label">密码</label>
                                <input type="password" class="form-control" id="sourcePassword">
                            </div>
                            <button type="button" id="testSourceBtn" class="btn btn-primary">测试连接</button>
                        </form>
                    </div>
                </div>
            </div>

            <!-- 目标数据库配置 -->
            <div class="col-md-6">
                <div class="card">
                    <div class="card-header">
                        <h5>目标数据库</h5>
                    </div>
                    <div class="card-body">
                        <form id="targetDbForm">
                            <div class="mb-3">
                                <label for="targetDbType" class="form-label">数据库类型</label>
                                <select class="form-select" id="targetDbType" required>
                                    <option value="0">SQL Server</option>
                                    <option value="1">MySQL</option>
                                    <option value="2">PostgreSQL</option>
                                    <option value="3">SQLite</option>
                                </select>
                            </div>
                            <div class="mb-3" id="targetServerField">
                                <label for="targetServer" class="form-label">服务器</label>
                                <input type="text" class="form-control" id="targetServer" placeholder="localhost">
                            </div>
                            <div class="mb-3" id="targetPortField">
                                <label for="targetPort" class="form-label">端口</label>
                                <input type="text" class="form-control" id="targetPort" placeholder="1433">
                            </div>
                            <div class="mb-3">
                                <label for="targetDatabase" class="form-label">数据库名</label>
                                <input type="text" class="form-control" id="targetDatabase" required>
                            </div>
                            <div class="mb-3" id="targetUsernameField">
                                <label for="targetUsername" class="form-label">用户名</label>
                                <input type="text" class="form-control" id="targetUsername">
                            </div>
                            <div class="mb-3" id="targetPasswordField">
                                <label for="targetPassword" class="form-label">密码</label>
                                <input type="password" class="form-control" id="targetPassword">
                            </div>
                            <button type="button" id="testTargetBtn" class="btn btn-primary">测试连接</button>
                        </form>
                    </div>
                </div>
            </div>
        </div>

        <!-- 表选择 -->
        <div class="card">
            <div class="card-header">
                <h5>选择要迁移的表</h5>
            </div>
            <div class="card-body">
                <div class="mb-3">
                    <button type="button" id="loadTablesBtn" class="btn btn-secondary mb-3">加载源数据库表</button>
                    <button type="button" id="viewForeignKeysBtn" class="btn btn-outline-info mb-3 ms-2"
                        disabled>查看表间关系</button>
                    <div class="form-check mb-2">
                        <input class="form-check-input" type="checkbox" id="selectAllTables" checked>
                        <label class="form-check-label" for="selectAllTables">
                            全选/取消全选
                        </label>
                    </div>
                </div>
                <div class="table-container">
                    <table class="table table-striped table-hover">
                        <thead>
                            <tr>
                                <th width="50">选择</th>
                                <th>表名</th>
                            </tr>
                        </thead>
                        <tbody id="tablesContainer">
                            <tr>
                                <td colspan="2" class="text-center">请先加载源数据库的表</td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>

        <!-- 表关系模态框 -->
        <div class="modal fade" id="foreignKeysModal" tabindex="-1" aria-labelledby="foreignKeysModalLabel"
            aria-hidden="true">
            <div class="modal-dialog modal-lg">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title" id="foreignKeysModalLabel">表间外键关系</h5>
                        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                    </div>
                    <div class="modal-body">
                        <!-- 标签页切换 -->
                        <ul class="nav nav-tabs mb-3" id="foreignKeysTabs" role="tablist">
                            <li class="nav-item" role="presentation">
                                <button class="nav-link active" id="table-tab" data-bs-toggle="tab"
                                    data-bs-target="#table-view" type="button" role="tab" aria-controls="table-view"
                                    aria-selected="true">表格视图</button>
                            </li>
                            <li class="nav-item" role="presentation">
                                <button class="nav-link" id="diagram-tab" data-bs-toggle="tab"
                                    data-bs-target="#diagram-view" type="button" role="tab" aria-controls="diagram-view"
                                    aria-selected="false">关系图</button>
                            </li>
                        </ul>

                        <!-- 标签页内容 -->
                        <div class="tab-content" id="foreignKeysTabContent">
                            <!-- 表格视图 -->
                            <div class="tab-pane fade show active" id="table-view" role="tabpanel"
                                aria-labelledby="table-tab">
                                <div class="table-container">
                                    <table class="table table-bordered">
                                        <thead>
                                            <tr>
                                                <th>表名</th>
                                                <th>列名</th>
                                                <th>引用表</th>
                                                <th>引用列</th>
                                                <th>删除规则</th>
                                                <th>更新规则</th>
                                            </tr>
                                        </thead>
                                        <tbody id="foreignKeysContainer">
                                            <tr>
                                                <td colspan="6" class="text-center">正在加载外键关系...</td>
                                            </tr>
                                        </tbody>
                                    </table>
                                </div>
                            </div>

                            <!-- 关系图视图 -->
                            <div class="tab-pane fade" id="diagram-view" role="tabpanel" aria-labelledby="diagram-tab">
                                <div id="relationshipDiagram" class="mt-2">
                                    <div class="text-center py-3">
                                        <div class="spinner-border text-primary" role="status">
                                            <span class="visually-hidden">正在加载...</span>
                                        </div>
                                        <p class="mt-2">正在生成关系图...</p>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
                    </div>
                </div>
            </div>
        </div>

        <!-- 迁移选项 -->
        <div class="card">
            <div class="card-header">
                <h5>迁移选项</h5>
            </div>
            <div class="card-body">
                <div class="form-check mb-2">
                    <input class="form-check-input" type="checkbox" id="migrateSchema" checked>
                    <label class="form-check-label" for="migrateSchema">
                        迁移表结构
                    </label>
                </div>
                <div class="form-check mb-2">
                    <input class="form-check-input" type="checkbox" id="migrateData" checked>
                    <label class="form-check-label" for="migrateData">
                        迁移表数据
                    </label>
                </div>
                <div class="form-check mb-2">
                    <input class="form-check-input" type="checkbox" id="processForeignKeys" checked>
                    <label class="form-check-label" for="processForeignKeys">
                        处理外键关系
                    </label>
                    <small class="d-block text-muted">启用此选项将识别并迁移表之间的外键关系，保持数据完整性约束</small>
                </div>
                <button type="button" id="startMigrationBtn" class="btn btn-success">开始迁移</button>
            </div>
        </div>

        <!-- 日志输出 -->
        <div class="card">
            <div class="card-header d-flex justify-content-between align-items-center">
                <h5>迁移日志</h5>
                <button type="button" id="clearLogBtn" class="btn btn-sm btn-outline-secondary">清空日志</button>
            </div>
            <div class="card-body">
                <pre id="logOutput" class="border p-3 bg-light"
                    style="max-height: 300px; overflow-y: auto;">准备就绪，等待操作...</pre>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        document.addEventListener('DOMContentLoaded', function () {
            // 初始化mermaid
            mermaid.initialize({
                startOnLoad: true,
                securityLevel: 'loose',
                theme: 'default',
                fontFamily: 'Arial',
                flowchart: {
                    htmlLabels: true,
                    curve: 'basis'
                },
                er: {
                    useMaxWidth: true
                }
            });

            // 显示/隐藏特定字段
            function toggleDbFields(dbType, prefix) {
                const serverField = document.getElementById(prefix + 'ServerField');
                const portField = document.getElementById(prefix + 'PortField');
                const usernameField = document.getElementById(prefix + 'UsernameField');
                const passwordField = document.getElementById(prefix + 'PasswordField');

                if (dbType === '3') { // SQLite
                    serverField.style.display = 'none';
                    portField.style.display = 'none';
                    usernameField.style.display = 'none';
                    passwordField.style.display = 'none';
                } else {
                    serverField.style.display = 'block';
                    portField.style.display = 'block';
                    usernameField.style.display = 'block';
                    passwordField.style.display = 'block';
                }
            }

            // 初始化表单字段显示
            document.getElementById('sourceDbType').addEventListener('change', function () {
                toggleDbFields(this.value, 'source');
            });

            document.getElementById('targetDbType').addEventListener('change', function () {
                toggleDbFields(this.value, 'target');
            });

            // 初始化
            toggleDbFields(document.getElementById('sourceDbType').value, 'source');
            toggleDbFields(document.getElementById('targetDbType').value, 'target');

            // 添加日志
            function addLog(message, isError = false) {
                const logOutput = document.getElementById('logOutput');
                const timestamp = new Date().toLocaleTimeString();
                const logClass = isError ? 'text-danger' : '';
                logOutput.innerHTML += `<div class="${logClass}">[${timestamp}] ${message}</div>`;
                logOutput.scrollTop = logOutput.scrollHeight;
            }

            // 清空日志
            document.getElementById('clearLogBtn').addEventListener('click', function () {
                document.getElementById('logOutput').innerHTML = '准备就绪，等待操作...';
            });

            // 外键处理控制逻辑
            document.getElementById('processForeignKeys').addEventListener('change', function () {
                if (this.checked) {
                    addLog('已启用外键关系处理，将迁移表间的约束关系');
                } else {
                    addLog('已禁用外键关系处理，表之间的约束关系将不会被迁移');
                }
            });

            // 当迁移模式选择变化时，更新外键处理状态
            document.getElementById('migrateSchema').addEventListener('change', function () {
                const fkCheckbox = document.getElementById('processForeignKeys');
                if (!this.checked) {
                    // 如果不迁移表结构，则禁用外键处理选项
                    fkCheckbox.disabled = true;
                    fkCheckbox.checked = false;
                    addLog('由于不迁移表结构，外键处理已被禁用');
                } else {
                    fkCheckbox.disabled = false;
                }
            });

            // 获取数据库连接信息
            function getDatabaseConnectionInfo(prefix) {
                const dbType = document.getElementById(prefix + 'DbType').value;
                const server = document.getElementById(prefix + 'Server').value;
                const port = document.getElementById(prefix + 'Port').value;
                const database = document.getElementById(prefix + 'Database').value;
                const username = document.getElementById(prefix + 'Username').value;
                const password = document.getElementById(prefix + 'Password').value;

                return {
                    databaseType: parseInt(dbType),
                    server: server,
                    port: port,
                    database: database,
                    username: username,
                    password: password
                };
            }

            // 测试源数据库连接
            document.getElementById('testSourceBtn').addEventListener('click', async function () {
                addLog('正在测试源数据库连接...');
                const connectionInfo = getDatabaseConnectionInfo('source');

                try {
                    const response = await fetch('/api/database/testConnection', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json'
                        },
                        body: JSON.stringify(connectionInfo)
                    });

                    const result = await response.json();

                    if (result.success) {
                        addLog(`源数据库连接成功！发现 ${result.tables.length} 个表。`);
                    } else {
                        addLog(`源数据库连接失败: ${result.error}`, true);
                    }
                } catch (error) {
                    addLog(`源数据库连接失败: ${error.message}`, true);
                }
            });

            // 测试目标数据库连接
            document.getElementById('testTargetBtn').addEventListener('click', async function () {
                addLog('正在测试目标数据库连接...');
                const connectionInfo = getDatabaseConnectionInfo('target');

                try {
                    const response = await fetch('/api/database/testConnection', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json'
                        },
                        body: JSON.stringify(connectionInfo)
                    });

                    const result = await response.json();

                    if (result.success) {
                        addLog(`目标数据库连接成功！发现 ${result.tables.length} 个表。`);
                    } else {
                        addLog(`目标数据库连接失败: ${result.error}`, true);
                    }
                } catch (error) {
                    addLog(`目标数据库连接失败: ${error.message}`, true);
                }
            });

            // 加载源数据库表
            document.getElementById('loadTablesBtn').addEventListener('click', async function () {
                addLog('正在加载源数据库表...');
                const connectionInfo = getDatabaseConnectionInfo('source');

                try {
                    const response = await fetch('/api/database/tables?' + new URLSearchParams({
                        databaseType: connectionInfo.databaseType,
                        server: connectionInfo.server,
                        port: connectionInfo.port,
                        database: connectionInfo.database,
                        username: connectionInfo.username,
                        password: connectionInfo.password
                    }));

                    if (!response.ok) {
                        const errorData = await response.json();
                        addLog(`加载表失败: ${errorData.error}`, true);
                        return;
                    }

                    const tables = await response.json();

                    if (tables.length === 0) {
                        addLog('源数据库中没有发现表');
                        document.getElementById('tablesContainer').innerHTML = '<tr><td colspan="2" class="text-center">没有发现表</td></tr>';
                        return;
                    }

                    let tableRows = '';
                    tables.forEach((table, index) => {
                        tableRows += `
                            <tr>
                                <td>
                                    <input class="form-check-input table-checkbox" type="checkbox" id="table-${index}" value="${table}" checked>
                                </td>
                                <td>${table}</td>
                            </tr>
                        `;
                    });

                    document.getElementById('tablesContainer').innerHTML = tableRows;
                    addLog(`成功加载 ${tables.length} 个表`);

                    // 启用查看表间关系按钮
                    document.getElementById('viewForeignKeysBtn').disabled = false;

                    // 全选/取消全选
                    document.getElementById('selectAllTables').addEventListener('change', function () {
                        const checkboxes = document.querySelectorAll('.table-checkbox');
                        checkboxes.forEach(checkbox => {
                            checkbox.checked = this.checked;
                        });
                    });
                } catch (error) {
                    addLog(`加载表失败: ${error.message}`, true);
                }
            });

            // 查看表间关系
            document.getElementById('viewForeignKeysBtn').addEventListener('click', async function () {
                const connectionInfo = getDatabaseConnectionInfo('source');
                const selectedTables = [];
                document.querySelectorAll('.table-checkbox:checked').forEach(checkbox => {
                    selectedTables.push(checkbox.value);
                });

                if (selectedTables.length === 0) {
                    addLog('请至少选择一个表查看其关系', true);
                    return;
                }

                // 表数量过多的警告
                if (selectedTables.length > 30) {
                    const confirmed = confirm(`您选择了${selectedTables.length}个表，数量较多可能会导致查询时间较长或请求超时。是否继续？`);
                    if (!confirmed) {
                        addLog('已取消查询表关系', false);
                        return;
                    }
                    addLog('正在处理大量表关系，请耐心等待...', false);
                }

                addLog('正在获取表间外键关系...');

                // 显示加载提示
                document.getElementById('foreignKeysContainer').innerHTML = '<tr><td colspan="6" class="text-center"><div class="spinner-border text-primary" role="status"></div><p class="mt-2">正在加载外键关系，这可能需要几分钟时间...</p></td></tr>';
                document.getElementById('relationshipDiagram').innerHTML = '<div class="text-center py-3"><div class="spinner-border text-primary" role="status"></div><p class="mt-2">正在生成关系图...</p></div>';

                try {
                    // 使用POST请求代替GET请求，避免URL过长问题
                    const requestBody = {
                        connectionInfo: connectionInfo,
                        tables: selectedTables
                    };

                    const response = await fetch('/api/database/foreignKeys', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json'
                        },
                        body: JSON.stringify(requestBody)
                    });

                    if (!response.ok) {
                        const errorData = await response.json();
                        addLog(`获取外键关系失败: ${errorData.error || errorData.message || '未知错误'}`, true);
                        return;
                    }

                    const foreignKeys = await response.json();

                    // 显示外键关系
                    let hasAnyRelations = false;
                    let tableRows = '';

                    for (const [tableName, relations] of Object.entries(foreignKeys)) {
                        if (relations.length > 0) {
                            hasAnyRelations = true;
                            relations.forEach(fk => {
                                tableRows += `
                                    <tr>
                                        <td>${fk.tableName}</td>
                                        <td>${fk.columnName}</td>
                                        <td>${fk.referencedTableName}</td>
                                        <td>${fk.referencedColumnName}</td>
                                        <td>${fk.deleteRule}</td>
                                        <td>${fk.updateRule}</td>
                                    </tr>
                                `;
                            });
                        }
                    }

                    if (!hasAnyRelations) {
                        tableRows = '<tr><td colspan="6" class="text-center">所选表之间没有发现外键关系</td></tr>';
                    }

                    document.getElementById('foreignKeysContainer').innerHTML = tableRows;

                    // 生成关系图
                    generateRelationshipDiagram(foreignKeys, selectedTables);

                    // 显示模态框
                    const foreignKeysModal = new bootstrap.Modal(document.getElementById('foreignKeysModal'));
                    foreignKeysModal.show();

                    // 监听标签页切换事件，以便在切换到关系图时正确渲染
                    document.getElementById('diagram-tab').addEventListener('shown.bs.tab', function () {
                        // 重新渲染mermaid图
                        mermaid.init(undefined, document.querySelector(".mermaid"));
                    });

                    addLog('已加载表间外键关系');
                } catch (error) {
                    addLog(`获取外键关系失败: ${error.message}`, true);
                }
            });

            // 生成表关系图
            function generateRelationshipDiagram(foreignKeys, selectedTables) {
                // 创建一个包含所有表的集合
                const allTables = new Set(selectedTables);

                // 创建Mermaid ER图定义
                let diagram = 'erDiagram\n';

                // 添加表之间的关系
                let hasRelations = false;

                for (const [tableName, relations] of Object.entries(foreignKeys)) {
                    if (relations.length > 0) {
                        relations.forEach(fk => {
                            if (allTables.has(fk.tableName) && allTables.has(fk.referencedTableName)) {
                                hasRelations = true;
                                // 添加关系线
                                let relationLine = `    ${fk.referencedTableName} ||--o{ ${fk.tableName} : "${fk.columnName}"\n`;
                                diagram += relationLine;
                            }
                        });
                    }
                }

                // 如果没有关系，添加提示信息
                if (!hasRelations) {
                    diagram = 'graph TD\n    A[所选表之间没有外键关系]';
                }

                // 更新关系图容器
                const relationshipContainer = document.getElementById('relationshipDiagram');
                relationshipContainer.innerHTML = `<pre class="mermaid">${diagram}</pre>`;
            }

            // 开始迁移
            document.getElementById('startMigrationBtn').addEventListener('click', async function () {
                // 获取选中的表
                const selectedTables = [];
                document.querySelectorAll('.table-checkbox:checked').forEach(checkbox => {
                    selectedTables.push(checkbox.value);
                });

                if (selectedTables.length === 0) {
                    addLog('请至少选择一个表进行迁移', true);
                    return;
                }

                const migrateSchema = document.getElementById('migrateSchema').checked;
                const migrateData = document.getElementById('migrateData').checked;
                const processForeignKeys = document.getElementById('processForeignKeys').checked;

                if (!migrateSchema && !migrateData) {
                    addLog('请至少选择一个迁移选项（结构或数据）', true);
                    return;
                }

                // 获取源数据库和目标数据库的连接信息
                const sourceConnectionInfo = getDatabaseConnectionInfo('source');
                const targetConnectionInfo = getDatabaseConnectionInfo('target');

                addLog('开始数据库迁移...');

                // 添加不同数据库类型之间常见的类型映射警告
                if (sourceConnectionInfo.databaseType !== targetConnectionInfo.databaseType) {
                    addLog('检测到源数据库与目标数据库类型不同，将进行自动类型映射：', false);

                    // 根据数据库类型显示常见的类型映射
                    if (sourceConnectionInfo.databaseType === 1 && targetConnectionInfo.databaseType === 2) { // MySQL到PostgreSQL
                        addLog('- MySQL [longtext, mediumtext, text, tinytext] → PostgreSQL [text]');
                        addLog('- MySQL [tinyint(1)] → PostgreSQL [boolean]');
                        addLog('- MySQL [int] → PostgreSQL [integer]');
                        addLog('- MySQL [blob类型] → PostgreSQL [bytea]');
                        addLog('- MySQL [enum, set] → PostgreSQL [text]');
                    } else if (sourceConnectionInfo.databaseType === 0 && targetConnectionInfo.databaseType === 2) { // SQL Server到PostgreSQL
                        addLog('- SQL Server [nvarchar, varchar, text] → PostgreSQL [text]');
                        addLog('- SQL Server [bit] → PostgreSQL [boolean]');
                        addLog('- SQL Server [uniqueidentifier] → PostgreSQL [uuid]');
                    } else if (sourceConnectionInfo.databaseType === 0 && targetConnectionInfo.databaseType === 1) { // SQL Server到MySQL
                        addLog('- SQL Server [nvarchar, varchar] → MySQL [varchar]');
                        addLog('- SQL Server [text, ntext] → MySQL [longtext]');
                    }

                    addLog('如果迁移过程中出现类型不兼容问题，请手动调整表结构', false);
                }

                const migrationRequest = {
                    sourceDatabase: sourceConnectionInfo,
                    targetDatabase: targetConnectionInfo,
                    migrateSchema: migrateSchema,
                    migrateData: migrateData,
                    processForeignKeys: processForeignKeys,
                    selectedTables: selectedTables
                };

                try {
                    const response = await fetch('/api/database/migrate', {
                        method: 'POST',
                        headers: {
                            'Content-Type': 'application/json'
                        },
                        body: JSON.stringify(migrationRequest)
                    });

                    const result = await response.json();

                    if (response.ok) {
                        addLog(`迁移完成: ${result.message}`);
                    } else {
                        addLog(`迁移失败: ${result.error}`, true);
                    }
                } catch (error) {
                    addLog(`迁移失败: ${error.message}`, true);
                }
            });
        });
    </script>
</body>

</html>